package com.gjs.management.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gjs.common.exception.BizException;
import com.gjs.common.microservice.api.IUserMicroService;
import com.gjs.common.pojo.dto.user.UserInfoDTO;
import com.gjs.common.pojo.dto.user.UserQueryDTO;
import com.gjs.management.mapper.ManagementStaffMapper;
import com.gjs.management.pojo.dto.staff.StaffQueryDTO;
import com.gjs.management.pojo.entity.*;
import com.gjs.management.pojo.vo.staff.ManagementStaffReqVO;
import com.gjs.management.pojo.vo.staff.ManagementStaffRspVO;
import com.gjs.management.service.*;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ManagementStaffServiceImpl extends ServiceImpl<ManagementStaffMapper, ManagementStaff> implements IManagementStaffService, UserDetailsService {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @DubboReference
    private IUserMicroService userMicroService;

    private final ISysUserRoleService userRoleService;

    private final ISysRoleService roleService;

    private final ISysRolePermissionService rolePermissionService;

    private final ISysPermissionService permissionService;

    @Override
    public UserDetails loadUserByUsername(String userSn) throws UsernameNotFoundException {
        ManagementStaff staff = this.getOne(new LambdaQueryWrapper<ManagementStaff>().eq(ManagementStaff::getUserSn,userSn));
        if(staff == null) {
            throw new UsernameNotFoundException("该用户非后台员工");
        }

        // 获取用户全部角色
        List<SysUserRole> userRoleList = userRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserSn,staff.getUserSn()));
        if(userRoleList == null){
            throw new BizException("员工未分配任何角色");
        }

        // 获取角色权限
        Set<Long> roleIdSet = userRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());
        List<SysRolePermission> sysRolePermissionList = rolePermissionService.list(new LambdaQueryWrapper<SysRolePermission>().in(SysRolePermission::getRoleId, roleIdSet));

        List<GrantedAuthority> authorities = AuthorityUtils.NO_AUTHORITIES;
        if(sysRolePermissionList != null && !sysRolePermissionList.isEmpty()){
            Set<Long> permissionIdSet= sysRolePermissionList.stream().map(SysRolePermission::getPermissionId).collect(Collectors.toSet());
            List<SysPermission> permissionList = permissionService.list(new LambdaQueryWrapper<SysPermission>().in(SysPermission::getId, permissionIdSet));
            if(permissionList != null && !permissionList.isEmpty()){
                List<String> permissionKeys = permissionList.stream().map(SysPermission::getPermissionKey).collect(Collectors.toList());
                authorities = AuthorityUtils.createAuthorityList(permissionKeys.toArray(new String[0]));
            }
        }
        return new User(userSn, passwordEncoder.encode(userSn), true, true, true, true, authorities);
    }

    @Override
    public UserInfoDTO getUserBySecurity() {
        return (UserInfoDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }

    @Override
    public Collection<? extends GrantedAuthority> getPermissionBySecurity() {
        return SecurityContextHolder.getContext().getAuthentication().getAuthorities();
    }

    @Override
    public ManagementStaffRspVO getManagementStaffRspVO(ManagementStaff staff){
        ManagementStaffRspVO managementStaffRspVO = BeanUtil.copyProperties(staff, ManagementStaffRspVO.class);

        // 获取员工用户信息
        UserQueryDTO userQueryDTO = new UserQueryDTO();
        userQueryDTO.setUserSn(managementStaffRspVO.getUserSn());
        managementStaffRspVO.setUserInfo(userMicroService.getOne(userQueryDTO));

        // 获取员工角色
        Set<Long> roleIdSet = userRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserSn,managementStaffRspVO.getUserSn()))
                .stream()
                .map(SysUserRole::getRoleId)
                .collect(Collectors.toSet());
        managementStaffRspVO.setRoleIdSet(roleIdSet);

        return managementStaffRspVO;
    }

    /**
     * 更新员工信息
     * 注意：这里不更新用户信息 因为这个功能其实应该在用户个人中心实现，而不是在管理系统 2022年3月31日 何金成
     * */
    @Override
    public Boolean updateRole(ManagementStaffReqVO staffReqVO){
        ManagementStaff staff = this.getById(staffReqVO.getId());
        if(staff == null){
            throw new BizException("找不到该员工");
        }

        // 更新员工关联角色
        List<SysRole> roleList = roleService.list(new LambdaQueryWrapper<SysRole>().in(SysRole::getId,staffReqVO.getRoleIdSet()));
        if(roleList.size() != staffReqVO.getRoleIdSet().size()){
            throw new BizException("部分角色不存在");
        }

        // 先清除被删除了的用户角色关系
        LambdaQueryWrapper<SysUserRole> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(SysUserRole::getUserSn,staff.getUserSn());
        deleteWrapper.notIn(SysUserRole::getRoleId,staffReqVO.getRoleIdSet());
        userRoleService.getBaseMapper().delete(deleteWrapper);

        // 求新旧权限之间的差集
        Set<Long> oldRoleIdSet = userRoleService.getBaseMapper()
                .selectObjs(new LambdaQueryWrapper<SysUserRole>().select(SysUserRole::getRoleId)).stream()
                .map(item -> Long.parseLong(item.toString()))
                .collect(Collectors.toSet());
        staffReqVO.getRoleIdSet().removeAll(oldRoleIdSet);

        for (Long roleId : staffReqVO.getRoleIdSet()) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserSn(staff.getUserSn());
            sysUserRole.setRoleId(roleId);
            boolean res = userRoleService.save(sysUserRole);
            if (!res) {
                throw new BizException("写入员工角色失败");
            }
        }

        return true;
    }

    @Override
    public Wrapper<ManagementStaff> buildWrapper(StaffQueryDTO queryDTO){
        LambdaQueryWrapper<ManagementStaff> wrapper = new LambdaQueryWrapper<>();

        // 如果有查询用户信息，则先调用微服务获取用户SN集合
        UserQueryDTO userInfoQuery = new UserQueryDTO();
        userInfoQuery.setMobile(queryDTO.getMobile());
        userInfoQuery.setNickname(queryDTO.getNickname());
        if(!BeanUtil.isEmpty(userInfoQuery)){
            List<String> userSnList = userMicroService.listUserSn(userInfoQuery);
            if(userSnList != null && !userSnList.isEmpty()){
                queryDTO.setUserSnSet(new HashSet(userSnList));
            }
        }

        wrapper.eq(queryDTO.getId() != null && queryDTO.getId() > 0,ManagementStaff::getId,queryDTO.getId());
        wrapper.eq(!StrUtil.isEmpty(queryDTO.getUserSn()),ManagementStaff::getUserSn,queryDTO.getUserSn());
        wrapper.in(queryDTO.getUserSnSet() != null && queryDTO.getUserSnSet().size() > 0,ManagementStaff::getUserSn,queryDTO.getUserSnSet());

        return wrapper;
    }
}
